﻿use actix_session::{Session, SessionExt, SessionGetError, SessionInsertError};
use actix_web::{dev::Payload, FromRequest, HttpRequest};
use std::future::{ready, Ready};
use uuid::Uuid;

pub struct TypedSession(Session);

impl TypedSession {
    const USER_ID_KEY: &'static str = "user_id";
    pub fn renew(&self) {
        self.0.renew()
    }

    pub fn insert_user_id(&self, user_id: Uuid) -> Result<(), SessionInsertError> {
        self.0.insert(Self::USER_ID_KEY, user_id)
    }
    pub fn get_user_id(&self) -> Result<Option<Uuid>, SessionGetError> {
        self.0.get(Self::USER_ID_KEY)
    }
    pub fn logout(&self) {
        self.0.purge()
    }
}

impl FromRequest for TypedSession {
    // 这是一种复杂的方式：我们返回的错误与 Session 的 FromRequest 实现返回相同的错误。
    type Error = <Session as FromRequest>::Error;

    // Rust 还不支持特质中的 async 语法
    // 从请求中期望一个 Future 作为返回类型，以允许使用需要执行异步操作的提取器（如 HTTP调用）
    // 我们还没有 Future，因为不执行任何 I/O，所以把 TypedSession 包装成 Ready
    // 然后把它转换成一个 Future，在执行器第一次轮询时解析为包装的值
    type Future = Ready<Result<TypedSession, Self::Error>>;

    fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future {
        ready(Ok(TypedSession(req.get_session())))
    }
}
